1 /* 2 * TouchGraph Software License 3 * 4 * 5 * Copyright (c) 2001 Alexander Shapiro. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * 3. The end-user documentation included with the redistribution, 20 * if any, must include the following acknowledgment: 21 * "This product includes software developed by 22 * TouchGraph (http://www.touchgraph.com/)." 23 * Alternately, this acknowledgment may appear in the software itself, 24 * if and wherever such third-party acknowledgments normally appear. 25 * 26 * 4. The name "TouchGraph" must not be used to endorse or promote 27 * products derived from this software without prior written 28 * permission. For written permission, please contact 29 * alex@touchgraph.com 30 * 31 * 5. Products derived from this software may not be called "TouchGraph", 32 * nor may "TouchGraph" appear in their name, without prior written 33 * permission of TouchGraph. 34 * 35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 38 * DISCLAIMED. IN NO EVENT SHALL TOUCHGRAPH OR ITS CONTRIBUTORS BE 39 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 40 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 41 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 42 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 43 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 44 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 45 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 * ===================================================================== 47 * 48 */ 49 50 package com.touchgraph.graphlayout.interaction; 51 52 import java.awt.event.*; 53 54 import javax.swing.JScrollBar; 55 56 import com.touchgraph.graphlayout.*; 57 58 /*** HyperScroll. Responsible for producing that neat hyperbolic effect. 59 * (Which isn't really hyperbolic, but just non-linear). 60 * Demonstrates the usefulness of Lenses. 61 * 62 * @author Alexander Shapiro 63 * @version 1.06 64 */ 65 public class HyperScroll implements GraphListener { 66 67 private JScrollBar hyperSB; 68 private TGPanel tgPanel; 69 HyperLens hyperLens; 70 double inverseArray[]=new double[200]; //Helps calculate the inverse of the Hyperbolic function 71 double width; //Initially was intended to change the function of the lens depending on screen size, 72 //but now functions as a constant. 73 74 public HyperScroll(TGPanel tgp) { 75 tgPanel=tgp; 76 hyperSB = new JScrollBar(JScrollBar.HORIZONTAL, 0, 8, 0, 108); 77 hyperSB.addAdjustmentListener(new hyperAdjustmentListener()); 78 79 hyperLens = new HyperLens(); 80 width= 2000;//tgPanel.getSize().width/2; 81 updateInverseArray(); 82 83 tgPanel.addGraphListener(this); 84 } 85 86 public JScrollBar getHyperSB() { return hyperSB; } 87 88 public HyperLens getLens() { return hyperLens; } 89 90 public void graphMoved() {} //From GraphListener interface 91 public void graphReset() { hyperSB.setValue(0); } //From GraphListener interface 92 93 private class hyperAdjustmentListener implements AdjustmentListener { 94 public void adjustmentValueChanged(AdjustmentEvent e) { 95 updateInverseArray(); 96 tgPanel.repaintAfterMove(); 97 } 98 } 99 100 double rawHyperDist (double dist) { //The hyperbolic transform 101 if(hyperSB.getValue()==0) return dist; 102 double hyperV=hyperSB.getValue(); 103 return Math.log(dist/(Math.pow(1.5,(70-hyperV)/40)*80) +1); 104 /* 105 double hyperD = Math.sqrt(dist+(10.1-Math.sqrt(hyperV)))-Math.sqrt(10.1-Math.sqrt(hyperV)); 106 */ 107 108 } 109 110 double hyperDist (double dist) { 111 112 double hyperV=hyperSB.getValue(); 113 //Points that are 250 away from the center stay fixed. 114 double hyperD= rawHyperDist(dist)/rawHyperDist(250)*250; 115 double fade=hyperV; 116 double fadeAdjust=100; 117 hyperD=hyperD*fade/fadeAdjust+dist*(fadeAdjust-fade)/fadeAdjust; 118 return hyperD; 119 120 } 121 122 void updateInverseArray(){ 123 double x; 124 for(int i=0;i<200;i++) { 125 x=width*i/200; //Points within a radius of 'width' will have exact inverses. 126 inverseArray[i]=hyperDist(x); 127 } 128 }; 129 130 int findInd(int min, int max, double dist) { 131 int mid=(min+max)/2; 132 if (inverseArray[mid]<dist) 133 if (max-mid==1) return max; 134 else return findInd(mid,max,dist); 135 else 136 if (mid-min==1) return mid; 137 else return findInd(min,mid,dist); 138 } 139 140 double invHyperDist (double dist) { //The inverse of hyperDist 141 142 if (dist==0) return 0; 143 int i; 144 if (inverseArray[199]<dist) i=199; 145 else i=findInd(0,199,dist); 146 double x2=inverseArray[i]; 147 double x1=inverseArray[i-1]; 148 double j= (dist-x1)/(x2-x1); 149 return(((double) i+j-1)/200.0*width); 150 } 151 152 153 class HyperLens extends TGAbstractLens { 154 protected void applyLens(TGPoint2D p) { 155 double dist=Math.sqrt(p.x*p.x+p.y*p.y); 156 if(dist>0) { 157 p.x=p.x/dist*hyperDist(dist); 158 p.y=p.y/dist*hyperDist(dist); 159 } 160 else { p.x =0; p.y=0;} 161 } 162 163 protected void undoLens(TGPoint2D p) { 164 double dist=Math.sqrt(p.x*p.x+p.y*p.y); 165 if(dist>0) { 166 p.x=p.x/dist*invHyperDist(dist); 167 p.y=p.y/dist*invHyperDist(dist); 168 } 169 else { p.x =0; p.y=0;} 170 } 171 } 172 173 //Things can't get much more complex then this, if you don't use an inverse function 174 /* 175 class HyperLens extends TGAbstractLens { 176 protected void applyLens(TGPoint2D p) { 177 if(p.x!=0) 178 p.x=p.x/Math.sqrt(Math.abs(p.x))*Math.sqrt(tgPanel.getSize().width/2); 179 if(p.y!=0) 180 p.y=p.y/Math.sqrt(Math.abs(p.y))*Math.sqrt(tgPanel.getSize().height/2); 181 } 182 183 protected void undoLens(TGPoint2D p) { 184 185 p.x=(p.x/Math.sqrt(tgPanel.getSize().width/2)); 186 p.x=p.x*Math.abs(p.x); 187 p.y=(p.y/Math.sqrt(tgPanel.getSize().height/2)); 188 p.y=p.y*Math.abs(p.y); 189 } 190 } 191 */ 192 193 } // end com.touchgraph.graphlayout.interaction.HyperScroll